chore(release): 0.16.4 — ADR-037 Slice B (wire-evidence echo on /gate) - #96
Merged
Conversation
* feat(sdk): wire-evidence echo capture from /gate response (ADR-037 Slice B) Implements the SDK-side of the protocol-3→4 additive bump. The backend's /gate response now echoes the SDK-supplied action_digest and a policy_hash slot (None today; Slice D wires per-request computation). Pre-v4 backends omit both keys entirely via skip_serializing_if = "Option::is_none", so the v4 SDK degrades cleanly to None on a v3 backend — no false positive. Source-side wiring: 1. NULLRUN_PROTOCOL_VERSION = 4 (src/nullrun/transport.py). The X-NULLRUN-PROTOCOL header now serialises the bumped value via the single source of truth; tests pin to str(NULLRUN_PROTOCOL_VERSION) so a future bump doesn't sweep this file again. NullRunProtocolError.user_action and docs/errors/NR-P001.md updated to point operators at X-NULLRUN-PROTOCOL: 4. 2. Two new contextvars in src/nullrun/context.py — _last_gate_action_digest_var, _last_gate_policy_hash_var — with public accessors get_last_gate_action_digest() / get_last_gate_policy_hash() and setters set_last_gate_action_digest() / set_last_gate_policy_hash(). clear_server_minted_execution_id also drops the v4 slots so a /check in one block never leaks a stale echo into a /track in a sibling block. 3. runtime._capture_wire_evidence (extracted from _capture_server_minted_execution_id so the two captures share a call site but have distinct log lines). Reads action_digest + policy_hash off the response, defensively validates type (drops non-str at WARNING), and stores into the contextvars. Called from _capture_server_minted_execution_id on the same /check lifetime so execution_id and action_digest always refer to the same gate decision. 4. ServerCapabilities.wire_evidence_echo (src/nullrun/capabilities.py) — informational flag surfaced by /api/v1/capabilities. NOT included in is_v3_ready() (informational, not a hard gate). Defaults to False on pre-v4 backends. 5. tests/test_slice_b_wire_evidence.py (10 new tests). Pins the SDK-side of the v3→4 additive bump: protocol-constant value, header serialisation, capture from /gate response (happy path, policy_hash-when-present, both-set), tolerance of pre-v4 backends, tolerance of malformed wire values, tolerance of non-dict response, clear semantics, source-of-truth wiring. 6. tests/test_capabilities.py — 2 new assertions: test_parse_capabilities_wire_evidence_echo_v4_backend and test_parse_capabilities_v4_protocol_range. 7. tests/contract/test_audit_wire.py + tests/test_v3_wire_contract.py — header assertions now source str(NULLRUN_PROTOCOL_VERSION) instead of the literal "3" so a future bump doesn't require sweeping either file. Class names kept for git-blame continuity. 8. README.md — alpha-status line + roadmap table updated: v0.15 → v0.15.x, v0.16 → v0.16.x with the new highlights, v0.17 for OpenTelemetry exporter / Redis-backed offline queue / hardened init contract that previously sat under v0.16. * docs: NR-P001 user_action bumps to protocol 4 reference NullRunProtocolError.user_action and docs/errors/NR-P001.md updated to point operators at X-NULLRUN-PROTOCOL: 4 (was 3). The v3→v4 bump is additive: min_protocol_version stays at 2, so v3 SDKs continue to work against a v4 backend. The new user_action tells operators running a pre-v4 SDK against a v4+ backend to upgrade. * chore(release): 0.16.4 — version bump + CHANGELOG - pyproject.toml + src/nullrun/__version__.py: 0.16.3 → 0.16.4. - CHANGELOG.md: insert [0.16.4] - 2026-08-31 at the top with full descriptions of the Slice B wire-evidence echo (capture helper, contextvars, capabilities flag, test pins), the protocol version bump, the wire-format additive nature, and the 1613/4 pytest + ruff-clean + mypy-clean verification status. Verified: pytest 1613 passed / 4 skipped (12 more than 0.16.3, accounting for the 10 new Slice B pins + 2 new capabilities assertions); ruff check src tests all checks pass; mypy src/nullrun no issues reported in 37 source files. No new wire fields beyond the two echoed slots — both fields echo already-computed values, no new hashing/computation introduced on either side. Refs: ADR-037 Slice B (2026-08-31); backend commit 8dbeaf4d (parity CI test analogue for SDK side); docs/errors/NR-P001.md.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Patch release — ADR-037 Slice B. Wire protocol 3 → 4 additively.
/gateresponse now echoes the SDK-suppliedaction_digestand apolicy_hashslot (alwaysNonetoday; Slice D wires per-request computation).min_protocol_versionstays at 2 so v3 SDKs are unaffected. Wire-format additive only — no new hashing/computation introduced on either side (both fields echo already-computed values).Highlights
NULLRUN_PROTOCOL_VERSION = 4— single source of truth atsrc/nullrun/transport.py; tests pin tostr(NULLRUN_PROTOCOL_VERSION)so a future bump doesn't sweep this file again.NullRunProtocolError.user_action+docs/errors/NR-P001.mdupdated to point operators atX-NULLRUN-PROTOCOL: 4.runtime._capture_wire_evidence— readsaction_digest+policy_hashoff the/gateresponse and stores into two new contextvars (_last_gate_action_digest_var,_last_gate_policy_hash_var). Defensive: drops non-str at WARNING, never raises. Called from_capture_server_minted_execution_idsoexecution_idandaction_digestalways refer to the same/checkdecision.ServerCapabilities.wire_evidence_echo— informational flag surfaced by/api/v1/capabilities. NOT inis_v3_ready()(informational, not a hard gate). Defaults toFalseon pre-v4 backends.tests/test_slice_b_wire_evidence.py(10 new tests) — pins the SDK-side of the v3→4 additive bump.tests/test_capabilities.py— 2 new assertions:test_parse_capabilities_wire_evidence_echo_v4_backend+test_parse_capabilities_v4_protocol_range.tests/contract/test_audit_wire.py+tests/test_v3_wire_contract.py— header assertions now sourcestr(NULLRUN_PROTOCOL_VERSION)instead of the literal"3"so a future bump doesn't require sweeping either file.Verification
tests/test_slice_b_wire_evidence.py— 10/10 pass.pytest -q1613 passed / 4 skipped (12 more than 0.16.3).ruff check src testsall checks pass.mypy src/nullrunno issues reported in 37 source files.Refs: ADR-037 Slice B (2026-08-31); backend commit 8dbeaf4d (parity CI test analogue); docs/errors/NR-P001.md.